/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       new_map_dialog.cpp

	$Header: /game/new_map_dialog.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "new_map_dialog.h"

#include <direct.h>
#include <fstream>
#include <io.h>
#include <string.h>
#include "adaptor_handler.h"
#include "adventure_frame.h"
#include "adventure_map.h"
#include "adventure_map_window.h"
#include "adventure_map_window_ptr.h"
#include "bitmap_group_cache.h"
#include "bitmap_group_window.h"
#include "bitmap_layer_window.h"
#include "bitmap_layer_cache_window.h"
#include "blend_window.h"
#include "bound_handler.h"
#include "button_cache.h"
#include "dialog_campaign.h"
#include "directory_changer.h"
#include "enum_operations.h"
#include "format_string.h"
#include "external_string.h"
#include "interface_help.h"
#include "item_help_block.h"
#include "main_menu.h"
#include "map_size.h"
#include "new_game_details.h"
#include "new_map_options_dialog.h"
#include "platform.h"
#include "scrollbar.h"
#include "standard_fonts.h"
#include "streambuf_operators.h"
#include "string_insensitive_compare.h"
#include "terrain.h"
#include "text_edit_window.h"
#include "text_window.h"
#include "toggle_button.h"
#include "town_properties.h"
#include "town_type.h"

extern t_button_cache g_large_button;
extern t_button_cache g_checkbox;
extern t_bitmap_group_cache const k_new_map_bitmaps("dialog.new_game");
extern t_bitmap_group_cache g_banners_55;
extern t_bitmap_group_cache g_difficulty_60_icons;
t_bitmap_group_cache  g_difficulty_icons( "difficulty_icons" );

extern t_external_string const k_text_map_description_title;

namespace
{
	const int k_line_item_height  = 30;
	const int k_line_item_spacing = k_line_item_height + 4;
	const int k_num_file_names = 10;


	// ---------------------------------------------------------------------------
	// class representing information about a subfolder
	// ---------------------------------------------------------------------------

	class t_subfolder_info : public t_new_map_file_info
	{
	public:
		explicit t_subfolder_info( std::string const & name );

		virtual std::string const &				get_description() const;
		virtual t_campaign_file_header *		get_file_header_ptr();
		virtual t_campaign_file_header const *	get_file_header_ptr() const;
		virtual std::string const &				get_file_name() const;
		virtual std::string const &				get_loss_condition() const;
		virtual std::string const &				get_name() const;
	    virtual int                             get_number_of_maps() const;
		virtual std::string const &				get_victory_condition() const;

	private:
		std::string	m_name;
	};

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	inline t_subfolder_info::t_subfolder_info( std::string const & name )
		:	m_name( name )
	{
	}

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	t_campaign_file_header * t_subfolder_info::get_file_header_ptr()
	{
		return 0;
	}

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	t_campaign_file_header const * t_subfolder_info::get_file_header_ptr() const
	{
		return 0;
	}

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	std::string const & t_subfolder_info::get_file_name() const
	{
		return m_name;
	}

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	std::string const & t_subfolder_info::get_name() const
	{
		return m_name;
	}

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	std::string const & t_subfolder_info::get_description() const
	{
		return m_name;
	}
	
    int t_subfolder_info::get_number_of_maps() const
    {
		return 0;
    }

	std::string const & t_subfolder_info::get_victory_condition() const
	{
		return m_name;
	}

	std::string const & t_subfolder_info::get_loss_condition() const
	{
		return m_name;
	}

	// ---------------------------------------------------------------------------
	// class representing information about a campaign file
	// ---------------------------------------------------------------------------

	class t_campaign_file_info : public t_new_map_file_info
	{
	public:
		t_campaign_file_info(
			std::string const &			file_name,
			t_campaign_file_header_ptr	file_header_ptr );

		virtual std::string const &				get_description() const;
		virtual t_campaign_file_header *		get_file_header_ptr();
		virtual t_campaign_file_header const *	get_file_header_ptr() const;
		virtual std::string const &				get_file_name() const;
		virtual std::string const &				get_loss_condition() const;
		virtual std::string const &				get_name() const;
		virtual int                             get_number_of_maps() const;
		virtual std::string const &				get_victory_condition() const;

	private:
		std::string					m_file_name;
		t_campaign_file_header_ptr	m_file_header_ptr;
	};

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	t_campaign_file_info::t_campaign_file_info(
		std::string const &			file_name,
		t_campaign_file_header_ptr	file_header_ptr )
		:	m_file_name( file_name ),
			m_file_header_ptr( file_header_ptr )
	{
		assert( m_file_header_ptr.get() != 0 );
	}

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	t_campaign_file_header * t_campaign_file_info::get_file_header_ptr()
	{
		return m_file_header_ptr.get();
	}

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	t_campaign_file_header const * t_campaign_file_info::get_file_header_ptr() const
	{
		return m_file_header_ptr.get();
	}

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	std::string const & t_campaign_file_info::get_file_name() const
	{
		return m_file_name;
	}

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	std::string const & t_campaign_file_info::get_name() const
	{
		return m_file_header_ptr->get_name();
	}

	// ---------------------------------------------------------------------------
	// Map description.
    // ---------------------------------------------------------------------------
	std::string const & t_campaign_file_info::get_description() const
	{
		return m_file_header_ptr->get_map_header( 0 ).description;
	}

	int t_campaign_file_info::get_number_of_maps() const
    {
		return m_file_header_ptr->get_map_count();
    }

    // ---------------------------------------------------------------------------
    // Victory condition.
    // ---------------------------------------------------------------------------
	std::string const & t_campaign_file_info::get_victory_condition() const
	{
		return m_file_header_ptr->get_map_header( 0 ).victory_condition;
	}

    // ---------------------------------------------------------------------------
    // Loss condition.
    // ---------------------------------------------------------------------------
	std::string const & t_campaign_file_info::get_loss_condition() const
	{
		return m_file_header_ptr->get_map_header( 0 ).loss_condition;
	}

	// ---------------------------------------------------------------------------
	// ---------------------------------------------------------------------------
	t_map_header const & get_map_header( t_new_map_file_info const & file_info )
	{
		t_campaign_file_header const * file_header_ptr = file_info.get_file_header_ptr();
		assert( file_header_ptr != 0 );
		assert( file_header_ptr->get_map_count() >= 1 );
		return file_header_ptr->get_map_header( 0 );
	}


	// ---------------------------------------------------------------------------
	// Do the dialogs that read in adventure maps
	// ---------------------------------------------------------------------------
	t_adventure_map_ptr do_adventure_map_dialogs( t_new_map_dialog * const & dialog )
	{
		t_campaign_file_header& file_header = dialog->get_file_header();
		std::string             file_name = dialog->get_file_name();

		if( file_header.is_multi_scenario() )
		{
			// First get the file header
			t_campaign_file_ref file_ref( file_name );
			t_multi_scenario_campaign_file_header_ptr file_header_ptr =
				create_multi_scenario_campaign_file_header( file_ref, 0 );

			if ( file_header_ptr.get() == 0 )
			{
				file_open_failure( file_ref );
				return 0;
			}

			t_counted_ptr< t_multi_scenario_dialog > dialog_ptr(
				new t_multi_scenario_dialog( t_window::get_main_window(), file_header_ptr, 0 ) );
			if ( !dialog_ptr->run_modal() )
				return 0;

			dialog->close();
			redraw_windows();

			// Create the player setup vector
			std::vector< t_player_setup > player_setups;
			create_default_player_setup_vector( file_header_ptr->get_map_header( 0 ) ).swap( player_setups );

			// Read the file to create the map
			return	read_game_file(
						t_window::get_main_window(),
						*file_header_ptr,
						file_ref,
						0,
						dialog_ptr->get_difficulty(),
						&player_setups[ 0 ],
						0,
						t_carryover_data_ptr(),
						dialog_ptr->guards_can_move() );
		} else
		{
			t_counted_ptr<t_new_map_options_dialog> options_dialog;
				
			options_dialog = new t_new_map_options_dialog( t_window::get_main_window(), file_header.get_map_header(0) );
			if (!options_dialog->run_modal())
				return 0;

			dialog->close();
			redraw_windows();

			return ( read_game_file(	t_window::get_main_window(), 
										file_header, file_name, 0, options_dialog->get_player_difficulty(),
										options_dialog->get_player_setup(),
										options_dialog->get_turn_duration(), 
										t_carryover_data_ptr(), 
										options_dialog->get_guards_move() ) );
		}
	}

}; // unnamed namespace

// ------------------------------------------------
// line item to display file information
// ------------------------------------------------
static t_external_string const k_text_map_name( "map_name" );

static void move_column( t_window* window, int x, int column_width, bool center )
{
	if (x < 0)
		window->set_visible( false );
	else
	{
		t_window*     parent = window->get_parent();
		t_screen_rect rect = parent->to_client( window->get_screen_rect() );

		if (center)
			x += (column_width - rect.width()) / 2;
		rect.right = x + rect.width();
		rect.left = x;
		window->move( rect );
		window->set_visible( true );
	}
}

// ------------------------------------------------
// line item to display file information
// ------------------------------------------------
void t_new_map_line::set_columns( int name_width, int size, int players, int humans, 
								  int allies, int difficulty, int map_count, int column_width )
{
	t_window*     parent = name_text->get_parent();
	t_screen_rect rect = parent->to_client( name_text->get_screen_rect() );

	rect.right = rect.left + name_width;
	name_text->move( rect );
	move_column( size_text, size, column_width, true );
	move_column( players_text, players, column_width, true );
	move_column( humans_text, humans, column_width, true );
	move_column( allies_text, allies, column_width, true );
	move_column( map_count_text, map_count, column_width, true );
}


void t_new_map_item::init( t_screen_point point, t_window* parent, t_button_group& group,
		                   t_screen_rect window_rect, int text_x, int line, 
						   t_handler_1<int> click_function,
					       t_handler_1<int> double_click_function, int column_width )

{
	int           width = window_rect.width();
	t_screen_rect rect(0,0,width,window_rect.height()); //k_line_item_height);
	t_cached_font font = get_font( window_rect.height() ); //k_line_item_height );
	t_help_block const& help = get_help_block( "campaign" );

	m_line_number = line;
	m_click_function = click_function;
	m_double_click_function = double_click_function;
	m_button = new t_toggle_button( point, parent, true );
	m_button->set_visible( false );
	m_button->set_click_handler( bound_handler( *this, &t_new_map_item::clicked ) );
	m_button->set_double_click_handler( bound_handler( *this, &t_new_map_item::double_clicked) );
	group.add( m_button );

	m_highlight_window = new t_window( rect, t_window::k_completely_transparent, m_button );
	m_normal_window = new t_window( rect, t_window::k_completely_transparent, m_button );
	m_button->set_released_image( m_normal_window );
	m_button->set_pressed_image( m_highlight_window );

	t_screen_rect text_rect( text_x, 0, width - 8, window_rect.height() );

	t_window* background;

	// add background for highlighted window
	background = new t_blend_window( t_pixel_24(0,0,200), 8, rect, m_highlight_window );

	// add map name
	t_pixel_24 black(0,0,0);
	t_pixel_24 white(255,255,255);
	t_pixel_24 light_gray(200,200,200);

	m_normal_line.name_text = new t_text_window( font, text_rect, 
		                                         m_normal_window, "", black);
	m_normal_line.name_text->set_drop_shadow( true, light_gray );
	m_normal_line.name_text->set_center_vertical();
	set_help( m_normal_line.name_text, help, "scenario_name" );
//	m_normal_line.name_text->set_help_balloon_text( k_text_map_name );

	m_highlight_line.name_text = new t_text_window( font, text_rect, 
		                                            m_highlight_window, "", white );
	m_highlight_line.name_text->set_drop_shadow( true );
	m_highlight_line.name_text->set_center_vertical();
	m_highlight_line.name_text->set_help_balloon_text( k_text_map_name );
	set_help( m_highlight_line.name_text, help, "scenario_name" );

	// add size item
	t_screen_rect item_rect(0,0, column_width, window_rect.height());

	m_normal_line.size_text = new t_text_window( font, item_rect,
		                                         m_normal_window, "", black );
	m_normal_line.size_text->set_drop_shadow( true, light_gray );
	m_normal_line.size_text->set_center_vertical();
	m_normal_line.size_text->set_center_horizontal();

	m_highlight_line.size_text = new t_text_window( font, item_rect,
		                                            m_highlight_window, "", white );
	m_highlight_line.size_text->set_drop_shadow( true, black );
	m_highlight_line.size_text->set_center_vertical();
	m_highlight_line.size_text->set_center_horizontal();

	// add players item
	m_normal_line.players_text = new t_text_window( font, item_rect,
		                                            m_normal_window, "", black );
	m_normal_line.players_text->set_drop_shadow( true, light_gray );
	m_normal_line.players_text->set_center_vertical();
	m_normal_line.players_text->set_center_horizontal();

	m_highlight_line.players_text = new t_text_window( font, item_rect,
		                                               m_highlight_window, "", white );
	m_highlight_line.players_text->set_drop_shadow( true, black );
	m_highlight_line.players_text->set_center_vertical();
	m_highlight_line.players_text->set_center_horizontal();

	// add humans item
	m_normal_line.humans_text = new t_text_window( font, item_rect,
		                                            m_normal_window, "", black );
	m_normal_line.humans_text->set_drop_shadow( true, light_gray );
	m_normal_line.humans_text->set_center_vertical();
	m_normal_line.humans_text->set_center_horizontal();

	m_highlight_line.humans_text = new t_text_window( font, item_rect,
		                                               m_highlight_window, "", white );
	m_highlight_line.humans_text->set_drop_shadow( true, black );
	m_highlight_line.humans_text->set_center_vertical();
	m_highlight_line.humans_text->set_center_horizontal();

	// add allies item
	m_normal_line.allies_text = new t_text_window( font, item_rect,
		                                            m_normal_window, "", black );
	m_normal_line.allies_text->set_drop_shadow( true, light_gray );
	m_normal_line.allies_text->set_center_vertical();
	m_normal_line.allies_text->set_center_horizontal();

	m_highlight_line.allies_text = new t_text_window( font, item_rect,
		                                               m_highlight_window, "", white );
	m_highlight_line.allies_text->set_drop_shadow( true, black );
	m_highlight_line.allies_text->set_center_vertical();
	m_highlight_line.allies_text->set_center_horizontal();

	// Add map count item
	m_normal_line.map_count_text = new t_text_window( font, item_rect,
		                                         m_normal_window, "", black );
	m_normal_line.map_count_text->set_drop_shadow( true, light_gray );
	m_normal_line.map_count_text->set_center_vertical();
	m_normal_line.map_count_text->set_center_horizontal();

	m_highlight_line.map_count_text = new t_text_window( font, item_rect,
		                                            m_highlight_window, "", white );
	m_highlight_line.map_count_text->set_drop_shadow( true, black );
	m_highlight_line.map_count_text->set_center_vertical();
	m_highlight_line.map_count_text->set_center_horizontal();

	// add bitmap items
	m_difficulty_image = new t_bitmap_layer_window( 0, t_screen_point(0,point.y), parent );
}

// ------------------------------------------------
// line item to display file information
// ------------------------------------------------
void t_new_map_item::clicked( t_button* button)
{
	if (button->is_pressed())
		m_click_function( m_line_number );
}

// ------------------------------------------------
// line item to display file information
// ------------------------------------------------
void t_new_map_item::double_clicked( t_button* button)
{
	if (button->is_pressed())
		m_double_click_function( m_line_number );
}


// ------------------------------------------------
// line item to display file information
// ------------------------------------------------
void t_new_map_item::set_columns( int name_width, int size, int players, int humans, int allies, 
								  int difficulty, int win, int loss, int map_count, 
								  int column_width )
{
	int offset = -m_button->to_parent( m_button->get_screen_rect().top_left() ).x;

	m_normal_line.set_columns( name_width, size + offset, players + offset, humans + offset,
							   allies + offset, difficulty + offset, map_count + offset,
							   column_width );
	m_highlight_line.set_columns( name_width, size + offset, players + offset, humans + offset,
								  allies + offset, difficulty + offset, map_count + offset,
								  column_width );
	move_column( m_difficulty_image, difficulty, column_width, true );
}

// ------------------------------------------------
// line item to display file information
// ------------------------------------------------
extern t_external_string const k_text_parent_folder;
t_external_string const k_text_parent_folder( "parent_folder" );
void t_new_map_item::set( t_new_map_file_info const& file_info )
{
	t_screen_point point;

	point = m_difficulty_image->get_screen_rect().top_left();
	point.x += m_difficulty_image->get_screen_rect().width() / 2;

	if (file_info.is_folder())
	{
		std::string const & name = file_info.get_name();
		std::string name_text = "[";

		if ( name.compare( ".." ) == 0)
			name_text += k_text_parent_folder;
		else
			name_text += name;
		name_text += "]";

		m_normal_line.name_text->set_text( name_text );
		m_highlight_line.name_text->set_text( name_text );
		m_normal_line.size_text->set_text( "" );
		m_highlight_line.size_text->set_text( "" );
		m_normal_line.players_text->set_text( "" );
		m_highlight_line.players_text->set_text( "" );
		m_normal_line.humans_text->set_text( "" );
		m_highlight_line.humans_text->set_text( "" );
		m_normal_line.allies_text->set_text( "" );
		m_highlight_line.allies_text->set_text( "" );
		m_normal_line.map_count_text->set_text( "" );
		m_highlight_line.map_count_text->set_text( "" );
		m_difficulty_image->set_bitmap( 0 );
	}
	else
	{

		std::string text = file_info.get_name();
		m_normal_line.name_text->set_text( text );
		m_highlight_line.name_text->set_text( text );

		t_map_header const & header = get_map_header( file_info );

		if (header.size <= k_small_map_size)
			text = "S";
		else if (header.size <= k_medium_map_size)
			text = "M";
		else if (header.size <= k_large_map_size)
			text = "L";
		else
			text = "XL";

		m_normal_line.size_text->set_text( text );
		m_highlight_line.size_text->set_text( text );

		format_string( "%i", header.players ).swap( text );
		m_normal_line.players_text->set_text( text );
		m_highlight_line.players_text->set_text( text );

		format_string( "%i", header.humans ).swap( text );
		m_normal_line.humans_text->set_text( text );
		m_highlight_line.humans_text->set_text( text );

		format_string( "%i", header.human_teams ).swap( text );
		m_normal_line.allies_text->set_text( text );
		m_highlight_line.allies_text->set_text( text );

		format_string( "%i", file_info.get_number_of_maps() ).swap( text );
		m_normal_line.map_count_text->set_text( text );
		m_highlight_line.map_count_text->set_text( text );

		m_difficulty_image->set_bitmap( m_map_dialog->get_difficulty_icon( header.difficulty ) );
	}
	point.x -= m_difficulty_image->get_screen_rect().width() / 2;
	point = m_difficulty_image->to_parent( point );
	m_difficulty_image->move( point );
}

// ------------------------------------------------
// line item to display file information
// ------------------------------------------------
void t_new_map_item::set_highlighted( bool arg )
{
	m_button->set_pressed( arg );
}

// ------------------------------------------------
// line item to display file information
// ------------------------------------------------
void t_new_map_item::set_visible( bool arg )
{
	m_button->set_visible( arg );
	m_difficulty_image->set_visible( arg && m_map_dialog->showing_difficulty() );
}

// ------------------------------------------------
// dialog to select a new map.
// ------------------------------------------------
extern char const* const		k_difficulty_icon_names[k_difficulty_count];
extern t_external_string const	k_text_cancel;
extern t_external_string const	k_text_cancel( "cancel" );
extern t_external_string const	k_text_next( "new_map_next.misc" );
extern t_external_string const	k_text_play_this_map( "play_map" );
static t_external_string const	k_text_choose_map_to_play( "choose_map" );
extern t_external_string const	k_text_cancel_help( "cancel" );

t_new_map_dialog::t_new_map_dialog( t_window* parent ) 
				: t_window( k_completely_transparent, parent )
{
	t_screen_rect rect;
	t_screen_rect parent_rect;
	t_help_block const&		shared_help = get_help_block( "shared" );
	t_help_block const&		help = get_help_block( "file_open" );

	// Initialize default values
	parent_rect = parent->get_client_rect();
	m_bitmaps = k_new_map_bitmaps.get();
	m_difficulty_bitmaps = g_difficulty_icons.get();	

	// center rect in parent window
	rect = m_bitmaps->get_rect();
	rect += t_screen_point( (parent_rect.width() - rect.width() ) / 2,
		                    (parent_rect.height() - rect.height() ) / 2 );
	rect.right += 5;
	rect.bottom += 5;

	// add background
	m_background = new t_bitmap_layer_window( m_bitmaps->find( "background" ), 
		                                      t_screen_point(0,0), this);
	m_background->set_drop_shadow( true );
	m_column_width = m_bitmaps->find( "column_width" )->get_width();

	// add cancel button
	t_button* button;

	button = new t_button( g_large_button.get(), find_location( "back_button"), m_background,
		                   k_text_cancel );
	button->set_click_handler( bound_handler( *this, &t_new_map_dialog::cancel ) );
	set_help ( button, shared_help, "cancel");
	
	// add begin button
	m_begin_button = new t_button( g_large_button.get(), find_location( "begin_button"),
		                           m_background, k_text_next );
	m_begin_button->set_click_handler( bound_handler( *this, &t_new_map_dialog::begin ) );
	set_help( m_begin_button, shared_help, "next" );
	//m_begin_button->set_help_balloon_text( k_text_play_this_map );

	create_controls();

	init( rect );
}

t_bitmap_layer const* t_new_map_dialog::get_difficulty_icon( int difficulty ) const
{
	return m_difficulty_bitmaps->find( k_difficulty_icon_names[difficulty] );
}


// ------------------------------------------------
// dialog to select a new map.
// find location to place a control
// ------------------------------------------------
t_screen_point t_new_map_dialog::find_location( std::string const& layer_name ) const
{
	t_bitmap_layer const* layer = m_bitmaps->find( layer_name.c_str() );

	return m_background->to_client( layer->get_rect().top_left() );
}

// ------------------------------------------------
// dialog to select a new map.
// create a toggle button with images in the bitmap_group
// ------------------------------------------------
t_toggle_button* t_new_map_dialog::create_toggle_button( std::string const& name, 
														 t_screen_point origin, 
														 t_sort_order sort_order,
														 t_window* parent )
{
	t_toggle_button*       button;
	t_screen_point         button_location;

	button_location = m_bitmaps->find( name + "_released" )->get_rect().top_left() - origin;

	button = new t_toggle_button( button_location, parent, true );
	set_button_layers( button, m_bitmaps, name );
	button->set_click_handler( add_2nd_argument( bound_handler( *this, &t_new_map_dialog::sort_maps ), 
		                                         sort_order ) );

	m_file_columns.add( button );

	return button;
}

// ------------------------------------------------
// dialog to select a new map.
// create controls for the scenario pane
// ------------------------------------------------
static t_screen_point const k_header_start( 8, 4 );
static int const            k_header_height = 40;
static int const            k_header_spacing = k_header_height + 4 + k_header_start.y;
static t_external_string const k_text_details( "details" );
static t_external_string const k_text_details_help( "details_help" );

void t_new_map_dialog::create_controls()
{
	t_window* child;
	t_screen_point origin = -m_background->get_screen_rect().top_left();
	t_screen_point offset;
	t_help_block const&		help = get_help_block( "file_open" );

	// add file grid
	t_text_window* label;
	t_bitmap_layer const* file_grid_bitmap = m_bitmaps->find( "choose_file_grid" );

	m_file_grid = new t_bitmap_layer_window( file_grid_bitmap, origin, m_background );
	m_line_rect = m_bitmaps->find( "line_width" )->get_rect()
				  - file_grid_bitmap->get_rect().top_left();

	// add labels to file grid

    offset = m_bitmaps->find( "map_title" )->get_rect().top_left() -
                file_grid_bitmap->get_rect().top_left();

	m_sort_order = k_sort_name;
	m_map_name_button = new t_toggle_button( offset, m_file_grid, true );
	label = new t_text_window( get_font( k_header_height ), 
		                       t_screen_rect( 0, 0, file_grid_bitmap->get_width() - 8,
							                  k_header_height + 4 ), m_map_name_button, 
					           k_text_map_name, t_pixel_24(0,0,0) );
	label->set_drop_shadow( true, t_pixel_24(200,200,200) );
	label->set_center_vertical();
	m_map_name_button->set_released_image( label );
	m_map_name_button->set_pressed();
	m_map_name_button->set_click_handler( add_2nd_argument( bound_handler( *this, 
		                                  &t_new_map_dialog::sort_maps ), k_sort_name ) );

	m_file_columns.add( m_map_name_button );

	m_show_size       = true;
	m_show_difficulty = true;
	m_show_players    = true;
	m_show_humans     = false;
	m_show_allies     = false;
	m_show_number_of_maps = false;
	m_show_victory    = false;
	m_show_loss       = false;

	// add line items for file grid
	t_screen_point point;
	int				text_x;
	int            line = 0;
	std::string    name;
    
    offset = file_grid_bitmap->get_rect().top_left();

    // Create file name buttons.
	m_lines.reserve( k_num_file_names ); // (m_file_grid->get_height() - point.y) / k_line_item_spacing );
	while (line < k_num_file_names) //point.y + k_line_item_height < m_file_grid->get_height())
	{
		name = format_string( "map_%d", line + 1 );
        point = m_bitmaps->find( name )->get_rect().top_left() - offset;
		text_x = point.x - m_line_rect.left;
		point.x = m_line_rect.left;

		m_lines.push_back( t_new_map_item( this ) );
		m_lines[line].init( point, m_file_grid, m_file_buttons,
                            m_line_rect, text_x, line, 
							bound_handler( *this, &t_new_map_dialog::file_clicked),
						    bound_handler( *this, &t_new_map_dialog::file_double_clicked ),
							m_column_width );
		//point.y += k_line_item_spacing;
		line++;
	}

	t_bitmap_layer const* vertical_line = m_bitmaps->find( "vertical_line" );
	int                   vertical_line_width = vertical_line->get_width();

	// compute point in client coordinates of file_grid
	point.x = m_file_grid->get_width() - m_column_width - vertical_line_width * 2;
	point.y = vertical_line->get_rect().top - file_grid_bitmap->get_rect().top;
	// subtract vertical_line origin, which is normally added in the bitmap_layer_window
	// constructor
	point -= vertical_line->get_rect().top_left();

	for (line = 0; line < 7; line++)
	{
		m_vertical_lines.push_back( new t_bitmap_layer_window( vertical_line, point, 
			                                                   m_file_grid ) );
		point.x -= m_column_width + vertical_line_width;
	}

	// create scrollbar
	t_bitmap_layer const* layer = m_bitmaps->find( "scrollbar" );
	t_screen_rect   rect = m_background->to_client( layer->get_rect() );

	m_file_scrollbar = new t_scrollbar( rect.top_left(), rect.height(), m_background, 0, 0 );
	m_file_scrollbar->set_handler( bound_handler( *this, &t_new_map_dialog::file_scroll ));
	m_file_scrollbar->set_page_size( m_lines.size() );

	// add column buttons
	// add size button
	t_screen_point grid_origin = file_grid_bitmap->get_rect().top_left();

	m_size_button		= create_toggle_button( "size", grid_origin, k_sort_size, m_file_grid );
	set_help ( m_size_button, help, "size");
	m_difficulty_button = create_toggle_button( "difficulty", grid_origin, k_sort_difficulty, m_file_grid );
	set_help ( m_difficulty_button, help, "difficulty");
	m_players_button	= create_toggle_button( "players", grid_origin, k_sort_players, m_file_grid );
	set_help ( m_players_button, help, "players");
	m_humans_button		= create_toggle_button( "humans", grid_origin, k_sort_humans, m_file_grid );
	set_help ( m_humans_button, help, "human players");
	m_allies_button		= create_toggle_button( "allies", grid_origin, k_sort_allies, m_file_grid );
	set_help ( m_allies_button, help, "allied");
	m_number_of_maps_button	= create_toggle_button( "maps", grid_origin, k_sort_number_of_maps, m_file_grid );
	set_help ( m_number_of_maps_button, help, "number_of_maps");
	//m_victory_button	= create_toggle_button( "win", grid_origin, k_sort_victory, m_file_grid );
	//m_loss_button		= create_toggle_button( "lose", grid_origin, k_sort_loss, m_file_grid );

	// add description box
	child = new t_bitmap_layer_window( m_bitmaps->find( "description_box" ),
		                               origin, m_background );

	rect = m_bitmaps->find( "description" )->get_rect() + origin;
	m_scenario_description = new t_text_window( get_font(16), rect, m_background, "", t_pixel_24(0,0,0) );
	m_scenario_description->set_drop_shadow( true, t_pixel_24( 200, 200, 200 ));

	// add details button
	t_button*             button;

	button = new t_button( g_large_button.get(), find_location( "details_button"),
		                   m_background, k_text_details );
	button->set_click_handler( bound_handler( *this, &t_new_map_dialog::scenario_details ) );
	set_help( button, help, "details" );
//	button->set_help_balloon_text( k_text_details_help );

	// read directory
	read_directory( "maps" );
	set_columns();
}


// ------------------------------------------------
// read files in directory
// ------------------------------------------------
void t_new_map_dialog::read_directory( std::string const& name )
{
	_finddata_t  file_data;
	int          handle;
	char const*  extension;

	{
		t_directory_changer changer( name.c_str() );
		m_folder = get_current_folder();
		if (m_folder[m_folder.length()-1] != '\\')
			m_folder += '\\';

		// read map files
		std::vector<t_new_map_file_info_ptr> new_folder_entries;
		handle = _findfirst( "*.*", &file_data );
		if (handle != -1)
		{
			do
			{
				if (file_data.attrib & _A_SUBDIR)
				{
					if (strcmp( file_data.name, "." ) == 0)
						continue;

					new_folder_entries.push_back( new t_subfolder_info( file_data.name ) );
					continue;
				}

				extension = strrchr( file_data.name, '.' );
				if (extension == 0 || stricmp( extension, ".h4c" ) != 0)
					continue;

				t_campaign_file_header_ptr file_header_ptr =
					create_campaign_file_header( std::string( file_data.name ), 0 );
				if ( file_header_ptr.get() != 0 )
					new_folder_entries.push_back( new t_campaign_file_info( file_data.name, file_header_ptr ) );
			} while (_findnext( handle, &file_data ) == 0);
		}
		m_folder_entries.swap( new_folder_entries );
	}

	m_file_scrollbar->set_limits( 0, m_folder_entries.size() - m_lines.size() );

	//Initializes dialog box selection data members
	m_top_line = 0;
	m_selected_item = 0;
	set_top_line( 0 );
	m_file_scrollbar->set_position( m_top_line );
	m_lines[0].set_highlighted();

	sort_maps( 0, m_sort_order );
	//This ensures that the first selected entry is NOT a subdirectory
	//unless there are no files in the current directory, in which case the first directory is highlighted
	for (unsigned int folder_entry_it = 0; folder_entry_it < m_folder_entries.size(); ++folder_entry_it) 
	{
		if (!m_folder_entries[ folder_entry_it ]->is_folder()) 
		{
            //Select first non-folder entry in the dialog box
			if (folder_entry_it >= m_lines.size())
			{
				set_top_line(folder_entry_it - m_lines.size() + 1);
				m_file_scrollbar->set_position( m_top_line );
				m_lines[m_lines.size()-1].set_highlighted();
			} else {
				m_lines[folder_entry_it].set_highlighted();
				
			}

			m_selected_item = folder_entry_it;			
			break;
		}
	}
	
}

// ------------------------------------------------------
// set positions of columns
// ------------------------------------------------------
void t_new_map_dialog::set_columns()
{
	int				line_width = m_vertical_lines.front()->get_width();
	int				x = m_line_rect.right;
	int size		= -100;
	int difficulty	= -100;
	int players		= -100;
	int humans		= -100;
	int allies		= -100;
	int map_count	= -100;
	int victory		= -100;
	int loss		= -100;

	if (m_show_loss)
	{
		x -= m_column_width + line_width;
		loss = x + line_width;
	}
	if (m_show_victory)
	{
		x -= m_column_width + line_width;
		victory = x + line_width;
	}
	if (m_show_number_of_maps)
	{
		x -= m_column_width + line_width;
		map_count = x + line_width;
	}
	if (m_show_allies)
	{
		x -= m_column_width + line_width;
		allies = x + line_width;
	}
	if (m_show_humans)
	{
		x -= m_column_width + line_width;
		humans = x + line_width;
	}
	if (m_show_players)
	{
		x -= m_column_width + line_width;
		players = x + line_width;
	}
	if (m_show_difficulty)
	{
		x -= m_column_width + line_width;
		difficulty = x + line_width;
	}
	if (m_show_size)
	{
		x -= m_column_width + line_width;
		size = x + line_width;
	}
	
	move_column( m_size_button, size, m_column_width, true);
	move_column( m_difficulty_button, difficulty, m_column_width, true );
	move_column( m_players_button, players, m_column_width, true );
	move_column( m_humans_button, humans, m_column_width, true);
	move_column( m_allies_button, allies, m_column_width, true);
	move_column( m_number_of_maps_button, map_count, m_column_width, true);

	// resize map name button
	t_screen_rect rect = m_file_grid->to_client( m_map_name_button->get_screen_rect() );

	rect.right = rect.left + x;
	m_map_name_button->move( rect );

	int index;

	for (index = 0; index < m_lines.size(); index++)
	{
		m_lines[index].set_columns( x, size, players, humans, allies, difficulty, victory,
									loss, map_count, m_column_width );
	}

	// show / hide vertical lines.
	t_window_list::iterator window;
	t_window*				line;
	int						line_position;

	for ( window = m_vertical_lines.begin(); window != m_vertical_lines.end(); window++ )
	{
		line = *window;
		line_position = m_file_grid->to_client( line->get_screen_rect() ).left;
		(*window)->set_visible( x - line_width <= line_position );
	}
}

// ------------------------------------------------------
// set top file
// ------------------------------------------------------
void t_new_map_dialog::set_top_line( int top_line )
{
	int line;
	int index;

	line = m_selected_item - m_top_line;
	if (line >= 0 && line < m_lines.size())
		m_lines[line].set_highlighted( false );
	m_top_line = top_line;

	// set line items according to header data.
	line = 0;
	for (index = top_line; index < m_folder_entries.size() && line < m_lines.size(); index++, line++)
	{
		m_lines[line].set( *m_folder_entries[index] );
		m_lines[line].set_visible();
	}
	// hide extra line items
	while (line < m_lines.size())
	{
		m_lines[line].set_visible( false );
		line++;
	}
	line = m_selected_item - m_top_line;
	if (line >= 0 && line < m_lines.size())
		m_lines[line].set_highlighted();
}

// ------------------------------------------------------
// respond to a file scroll event
// ------------------------------------------------------
void t_new_map_dialog::file_scroll( t_scrollbar* scrollbar, int line )
{
	set_top_line( line );
}



// ------------------------------------------------------
// set selected file
// ------------------------------------------------------
void t_new_map_dialog::set_highlight( int line )
{
	int old_selection = m_selected_item;

	m_selected_item = m_top_line + line;
	if (m_selected_item == old_selection)
		return;
	if (m_selected_item < 0 || m_selected_item >= m_folder_entries.size())
	{
		m_begin_button->enable( false );
		return;
	}

	// save player names
	if (m_folder_entries[m_selected_item]->is_folder())
	{
		m_begin_button->enable( false );
		return;
	}

	t_map_header const& header = get_map_header( *m_folder_entries[ m_selected_item ] );

	m_begin_button->enable();

}

// ------------------------------------------------------
// File clicked
// ------------------------------------------------------
void t_new_map_dialog::file_clicked( int line )
{
	int item = line + m_top_line;

	if (item >= m_folder_entries.size())
		return;

	set_highlight( line );
	
    if (m_folder_entries[item]->is_folder())
        return;

	std::string text;

	text = k_text_map_description_title.get() + ":\n";
	text += m_folder_entries[item]->get_description();
	
	m_scenario_description->set_text( text );
}

// ------------------------------------------------------
// record double click
// ------------------------------------------------------
void t_new_map_dialog::file_double_clicked( int line )
{
	int item = line + m_top_line;

	if (item >= m_folder_entries.size())
		return;

	if (m_folder_entries[item]->is_folder())
	{
		std::string start_folder = get_current_folder();

		chdir( m_folder.c_str() );
		read_directory( m_folder_entries[item]->get_name() );
		chdir( start_folder.c_str());
		return;
	}

	set_visible( false );

	if( ( m_adventure_map_ptr = do_adventure_map_dialogs( this ) ) == 0 )
	{
		set_visible( true );
		return;
	}


	m_return_value = 1;
	close();
}


// ------------------------------------------------
// dialog to select a new map.
// begin game
// ------------------------------------------------
void t_new_map_dialog::begin( t_button* )
{
	set_visible( false );

	if( ( m_adventure_map_ptr = do_adventure_map_dialogs( this ) ) == 0 )
	{
		set_visible( true );
		return;
	}


	m_return_value = 1;
	close();
}

// ------------------------------------------------
// dialog to select a new map.
// cancel dialog
// ------------------------------------------------
void t_new_map_dialog::cancel( t_button* )
{
	m_return_value = 0;
	close();
}


// ------------------------------------------------
// dialog to select a new map.
// open dialog to determine details in list
// -------------------------------------------------
void t_new_map_dialog::scenario_details( t_button* button )
{
	t_counted_ptr<t_new_game_details_dialog> dialog
		= new t_new_game_details_dialog( m_show_size, m_show_difficulty,
		                                 m_show_players, m_show_humans,
										 m_show_allies, m_show_number_of_maps, get_parent() );

	if (!dialog->run_modal())
		return;


	m_show_size       = dialog->size_checked();
	m_show_difficulty = dialog->difficulty_checked();
	m_show_players    = dialog->players_checked();
	m_show_humans     = dialog->humans_checked();
	m_show_allies     = dialog->allies_checked();
	m_show_number_of_maps = dialog->number_of_maps_checked();
	set_columns();
}

// ------------------------------------------------
// sort order objects
// ------------------------------------------------
namespace
{
	class t_sort_name
	{
	public:
		bool operator()( t_new_map_file_info_ptr const& left, t_new_map_file_info_ptr const& right )
		{
			bool left_is_folder = left->is_folder();
			bool right_is_folder = right->is_folder();
			if (left_is_folder && !right_is_folder)
				return true;
			if (right_is_folder && !left_is_folder)
				return false;

			int name_compare = string_insensitive_compare( left->get_name(), right->get_name() );
			return		name_compare < 0
					||	(	name_compare == 0
						&&	string_insensitive_compare( left->get_file_name(), right->get_file_name() ) < 0 );
		}
	};

	class t_sort_allies : public t_sort_name
	{
	public:
		bool operator()( t_new_map_file_info_ptr const& left, t_new_map_file_info_ptr const& right )
		{
			if ( left->is_folder() || right->is_folder() )
				return t_sort_name::operator()( left, right );
			int left_value = get_map_header( *left ).human_teams;
			int right_value = get_map_header( *right ).human_teams;
			return left_value < right_value || ( left_value == right_value && t_sort_name::operator()( left, right ) );
		}
	};

	class t_sort_difficulty : public t_sort_name
	{
	public:
		bool operator()( t_new_map_file_info_ptr const& left, t_new_map_file_info_ptr const& right )
		{
			if ( left->is_folder() || right->is_folder() )
				return t_sort_name::operator()( left, right );
			t_difficulty left_value = get_map_header( *left ).difficulty;
			t_difficulty right_value = get_map_header( *right ).difficulty;
			return left_value < right_value || ( left_value == right_value && t_sort_name::operator()( left, right ) );
		}
	};

	class t_sort_humans : public t_sort_name
	{
	public:
		bool operator()( t_new_map_file_info_ptr const& left, t_new_map_file_info_ptr const& right )
		{
			if ( left->is_folder() || right->is_folder() )
				return t_sort_name::operator()( left, right );
			int left_value = get_map_header( *left ).humans;
			int right_value = get_map_header( *right ).humans;
			return left_value < right_value || ( left_value == right_value && t_sort_name::operator()( left, right ) );
		}
	};
	
	class t_sort_loss : public t_sort_name
	{
	public:
		bool operator()( t_new_map_file_info_ptr const& left, t_new_map_file_info_ptr const& right )
		{
			if ( left->is_folder() || right->is_folder() )
				return t_sort_name::operator()( left, right );
			std::string const & left_value = get_map_header( *left ).loss_condition;
			std::string const & right_value = get_map_header( *right ).loss_condition;
			int compare = string_insensitive_compare( left_value, right_value );
			return compare < 0 || ( compare == 0 && t_sort_name::operator()( left, right ) );
		}
	};

	class t_sort_players : public t_sort_name
	{
	public:
		bool operator()( t_new_map_file_info_ptr const& left, t_new_map_file_info_ptr const& right )
		{
			if ( left->is_folder() || right->is_folder() )
				return t_sort_name::operator()( left, right );
			int left_value = get_map_header( *left ).players;
			int right_value = get_map_header( *right ).players;
			return left_value < right_value || ( left_value == right_value && t_sort_name::operator()( left, right ) );
		}
	};

	class t_sort_size : public t_sort_name
	{
	public:
		bool operator()( t_new_map_file_info_ptr const& left, t_new_map_file_info_ptr const& right )
		{
			if ( left->is_folder() || right->is_folder() )
				return t_sort_name::operator()( left, right );
			int left_value = get_map_header( *left ).size;
			int right_value = get_map_header( *right ).size;
			return left_value < right_value || ( left_value == right_value && t_sort_name::operator()( left, right ) );
		}
	};

	class t_sort_map_count : public t_sort_name
	{
	public:
		bool operator()( t_new_map_file_info_ptr const& left, t_new_map_file_info_ptr const& right )
		{
			if ( left->is_folder() || right->is_folder() )
				return t_sort_name::operator()( left, right );
			int left_value = left->get_number_of_maps();
			int right_value = right->get_number_of_maps();
			return left_value < right_value || ( left_value == right_value && t_sort_name::operator()( left, right ) );
		}
	};

	class t_sort_victory : public t_sort_name
	{
	public:
		bool operator()( t_new_map_file_info_ptr const& left, t_new_map_file_info_ptr const& right )
		{
			if ( left->is_folder() || right->is_folder() )
				return t_sort_name::operator()( left, right );
			std::string const & left_value = get_map_header( *left ).victory_condition;
			std::string const & right_value = get_map_header( *right ).victory_condition;
			int compare = string_insensitive_compare( left_value, right_value );
			return compare < 0 || ( compare == 0 && t_sort_name::operator()( left, right ) );
		}
	};

}; // end unnamed namespace

// ------------------------------------------------
// sort maps
// ------------------------------------------------
void t_new_map_dialog::sort_maps( t_button*, t_sort_order sort_order )
{
	t_new_map_file_info_ptr old_folder_entry;

	// preserve current selection, if it exists.  Otherwise preserve top item.
	if (m_selected_item >= 0)
		old_folder_entry = m_folder_entries[m_selected_item];
	else
		old_folder_entry = m_folder_entries[m_top_line];

	switch (sort_order)
	{
		case k_sort_allies:
			std::sort( m_folder_entries.begin(), m_folder_entries.end(), t_sort_allies() );
			break;

		case k_sort_difficulty:
			std::sort( m_folder_entries.begin(), m_folder_entries.end(), t_sort_difficulty() );
			break;

		case k_sort_humans:
			std::sort( m_folder_entries.begin(), m_folder_entries.end(), t_sort_humans() );
			break;

		case k_sort_loss:
			std::sort( m_folder_entries.begin(), m_folder_entries.end(), t_sort_loss() );
			break;

		case k_sort_name:
			std::sort( m_folder_entries.begin(), m_folder_entries.end(), t_sort_name() );
			break;

		case k_sort_players:
			std::sort( m_folder_entries.begin(), m_folder_entries.end(), t_sort_players() );
			break;

		case k_sort_size:
			std::sort( m_folder_entries.begin(), m_folder_entries.end(), t_sort_size() );
			break;
			 
		case k_sort_number_of_maps:
			std::sort( m_folder_entries.begin(), m_folder_entries.end(), t_sort_map_count() );
			break;
			 
		case k_sort_victory:
			std::sort( m_folder_entries.begin(), m_folder_entries.end(), t_sort_victory() );
			break;
	}

	// restore current selection, or top item, whichever is appropriate.
	std::string const & old_file_name = old_folder_entry->get_file_name();
	int folder_entry_count = m_folder_entries.size();
	int item;
	for ( item = 0; item < folder_entry_count; item++ )
		if ( string_insensitive_compare( old_file_name, m_folder_entries[item]->get_file_name() ) == 0 )
			break;

	if (m_selected_item >= 0)
	{
		m_top_line = m_top_line - m_selected_item + item;
		m_selected_item = item;
	}
	else
		m_top_line = item;

	if (m_top_line + m_lines.size() > folder_entry_count)
		m_top_line = folder_entry_count - m_lines.size();
	if (m_top_line < 0)
		m_top_line = 0;
	set_top_line( m_top_line );
	m_file_scrollbar->set_position( m_top_line );
}



